]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st: Generate shadows from the silhouette of the source texture
authorDaniel van Vugt <daniel.van.vugt@canonical.com>
Fri, 16 Jul 2021 10:34:11 +0000 (18:34 +0800)
committerMarge Bot <marge-bot@gnome.org>
Sat, 5 Mar 2022 13:55:37 +0000 (13:55 +0000)
As first mentioned in commit 672171093, the CSS spec defines shadow
colors independently from the colors casting the shadow. It's not
a physical light simulation so a shadow is allowed to be a different
color from texture casting it.

This means we only care about the shape of the source where alpha
values of zero are adjacent to alpha values of non-zero. And all such
non-zero pixels should be treated as fully opaque for the purpose of
shadow generation. While this would be wrong for a physical light
simulation it does allow us to cast shadows around semi-translucent
shapes and better support CSS.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4477
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1918>

src/st/st-private.c

index 540bad425ebe2766bdb5f83dd06355e2a5637f5f..bb981516dc8ac8a2dfee156840cc47e28a46309b 100644 (file)
@@ -394,7 +394,10 @@ _st_create_shadow_pipeline (StShadow    *shadow_spec,
   float sigma;
   int src_height, dst_height;
   int src_width, dst_width;
+  CoglPipeline *texture_pipeline;
 
+  static CoglPipelineKey texture_pipeline_key =
+    "st-create-shadow-pipeline-saturate-alpha";
   static CoglPipeline *shadow_pipeline_template = NULL;
 
   g_return_val_if_fail (shadow_spec != NULL, NULL);
@@ -433,10 +436,34 @@ _st_create_shadow_pipeline (StShadow    *shadow_spec,
                                     });
 
   /* Texture */
-  texture_node = clutter_texture_node_new (src_texture,
-                                           0,
-                                           CLUTTER_SCALING_FILTER_NEAREST,
-                                           CLUTTER_SCALING_FILTER_NEAREST);
+  texture_pipeline = cogl_context_get_named_pipeline (ctx,
+                                                      &texture_pipeline_key);
+
+  if (G_UNLIKELY (texture_pipeline == NULL))
+    {
+      CoglSnippet *snippet;
+
+      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+                                  "",
+                                  "if (cogl_color_out.a > 0.0)\n"
+                                  "  cogl_color_out.a = 1.0;");
+
+      texture_pipeline = cogl_pipeline_new (ctx);
+      cogl_pipeline_add_snippet (texture_pipeline, snippet);
+      cogl_object_unref (snippet);
+
+      cogl_context_set_named_pipeline (ctx,
+                                       &texture_pipeline_key,
+                                       texture_pipeline);
+    }
+
+  /* No need to unref texture_pipeline since the named pipeline hash
+   * doesn't change its ref count from 1. Also no need to copy texture_pipeline
+   * since we'll be completely finished with it after clutter_paint_node_paint.
+   */
+
+  cogl_pipeline_set_layer_texture (texture_pipeline, 0, src_texture);
+  texture_node = clutter_pipeline_node_new (texture_pipeline);
   clutter_paint_node_add_child (blur_node, texture_node);
   clutter_paint_node_add_rectangle (texture_node,
                                     &(ClutterActorBox) {